﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VCDIFF.Visit;
using VCDIFF.Tools;

namespace VCDIFF
{
    public class Header
    {
        /*
        Header organization
            Header1                                  - byte
            Header2                                  - byte
            Header3                                  - byte
            Header4                                  - byte
            Hdr_Indicator                            - byte
            [Secondary compressor ID]                - byte
            [Length of code table data]              - integer
            [Code table data]
                Size of near cache                   - byte
                Size of same cache                   - byte
                Compressed code table data
         */

        public byte Header1 { get; set; }
        public byte Header2 { get; set; }
        public byte Header3 { get; set; }
        public byte Header4 { get; set; }
        public byte HdrIndicator { get; set; }
        public byte SecondaryCompressorId { get; set; }
        public UInt64 CodeTableDataLength { get; set; }
        public byte NearCacheSize { get; set; }
        public byte SameCacheSize { get; set; }

        public void SetHeader(Header header)
        {
            Header1 = header.Header1;
            Header2 = header.Header2;
            Header3 = header.Header3;
            Header4 = header.Header4;
            HdrIndicator = header.HdrIndicator;
            SecondaryCompressorId = header.SecondaryCompressorId;
            CodeTableDataLength = header.CodeTableDataLength;
            NearCacheSize = header.NearCacheSize;
            SameCacheSize = header.SameCacheSize;
        }

        public void Read(Reader reader)
        {
            reader.Visit(this);
        }

        public void Write(Writer writer)
        {
            writer.Visit(this);
        }        

        public byte[] GetHeaderData()
        {
            UInt64 index = 0;
            byte[] headerData = new byte[GetHeaderSize()];
            headerData[index++] = Header1;
            headerData[index++] = Header2;
            headerData[index++] = Header3;
            headerData[index++] = Header4;
            headerData[index++] = HdrIndicator;
            headerData[index++] = SecondaryCompressorId;

            foreach (byte b in SFIOInteger.Encode(CodeTableDataLength))
                headerData[index++] = b;

            headerData[index++] = NearCacheSize;
            headerData[index++] = SameCacheSize;

            return headerData;
        }

        public string GetHeaderString()
        {
            StringBuilder headerString = new StringBuilder();
            headerString.Append(Header1);
            headerString.Append(Header2);
            headerString.Append(Header3);
            headerString.Append(Header4);
            headerString.Append(HdrIndicator);
            headerString.Append(SecondaryCompressorId);

            foreach (byte b in SFIOInteger.Encode(CodeTableDataLength))
                headerString.Append(b);

            headerString.Append(NearCacheSize);
            headerString.Append(SameCacheSize);

            return headerString.ToString();
        }

        public UInt64 GetHeaderSize()
        {
            // Header1 + Header2 + Header3 + Header4 + Hdr_Indicator + Secondary compressor ID + Size of near cache + Size of same cache
            UInt64 headerSize = 8;
            // Length of code table data
            headerSize += SFIOInteger.Size(SFIOInteger.Encode(CodeTableDataLength)) + 1;

            return headerSize;
        }
    }
}
